package no.ntnu.fp.su;

import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Timer classen som kaller {@link PollDataTimer} dersom du kjører {@link Watch}
 * , og {@link GetDataTimerTask} dersom {@link Master}
 * 
 * @author stn
 * 
 */
public class ControlSystem {
	private Timer timer;

	/**
	 * Retunerer timeren
	 * 
	 * @return {@link Timer} - timeren som taskene kjøres på
	 */
	public Timer getTimer() {
		return timer;
	}

	private ArrayList<PollDataTimer> tasks;

	/**
	 * Constructor, lager og starter Timeren
	 */
	public ControlSystem() {
		tasks = new ArrayList<PollDataTimer>();
		System.out.println("ControlSystem created, starting Timer");
		timer = new Timer();
		System.out.println("Timer created");
	}

	/**
	 * Legger til en {@link Database} poller for {@link Master} som leser
	 * brønnverdier fra Databasen
	 * 
	 * @param {@link WatchWell} - Brønn som skal polles
	 */
	public void addDBpoller(WatchWell w) {
		timer.scheduleAtFixedRate(new GetDataTimerTask(w), 5000 + (int) (Math
				.random() * Log.DB_WRITE_BUFFER_TIME) * 1000,
				Log.DB_WRITE_BUFFER_TIME * 1000);
	}

	/**
	 * Legger en {@link WatchWell} til for sampling hvert sekund
	 * 
	 * @param {@link WatchWell} - Brønn som skal samples hvert sekund
	 */
	public void addWell(WatchWell w) {
		System.out.println("Adding Well to task list, w =" + w.getName());
		System.out.println(w);
		tasks.add(new PollDataTimer(w));
		System.out.println(w.getName() + " added, scheduling");
		timer.scheduleAtFixedRate(tasks.get(tasks.size() - 1), (int) (Math
				.random() * 1000), 1000);
	}

	/**
	 * Ittererer gjennom tillagte {@link WatchWell} og fjerner dersom finner den
	 * spesifiserte
	 * 
	 * @param {@link WatchWell} - Brønn som skal fjernes fra sampleliste
	 */
	public synchronized void removeWell(WatchWell w) {
		for (PollDataTimer pdt : tasks) {
			if (pdt.getWell() == w) {
				System.out.println("Removing " + w.getName() + " from CS");
				pdt.cancel();
				tasks.remove(pdt);
				return;
			}
		}
		System.out.println("Failed to remove " + w.getName());
	}

	/**
	 * Klasse som kjøres hvert sekund fra {@link ControlSystem}, og henter ut
	 * data fra brønner
	 * 
	 * @author stn
	 * 
	 */
	class PollDataTimer extends TimerTask {

		private WatchWell watchWell;

		/**
		 * Constructor, tar {@link WatchWell} som skal polles
		 * 
		 * @param {@link WatchWell} - Brønn som skal samples
		 */
		public PollDataTimer(WatchWell w) {
			watchWell = w;
		}

		/**
		 * Gir brønnen denne tasken poller data fra
		 * 
		 * @return {@link WatchWell} som polles
		 */
		public WatchWell getWell() {
			return watchWell;
		}

		/**
		 * Kalles hvert sekund fra timer i ControlSystem
		 */
		public void run() {
			// System.out.println("Polling data from " + watchWell.getName());
			watchWell.updateData(watchWell.getWell().sample());
			watchWell.interrupt(); // gi beskjed om ny data
		}

	}

	/**
	 * Klasse som henter siste brønndata fra {@link Database} for {@link Master}
	 * 
	 * @author stn
	 * 
	 */
	class GetDataTimerTask extends TimerTask {

		private WatchWell well;

		/**
		 * Constructor
		 * 
		 * @param {@link WatchWell} - Brønn som data skal hentes for
		 */
		GetDataTimerTask(WatchWell w) {
			well = w;
			well.getLog().updateFromDBinit();
		}

		/**
		 * Kalles hver DB_WRITE_BUFFER_TIME sekund fra
		 * {@link ControlSystem}.<br>
		 * Henter data fra {@link Database}.
		 * 
		 * @see Log#DB_WRITE_BUFFER_TIME
		 */
		public void run() {
			well.getLog().updateFromDB();
			well.updateStatus();

		}

	}

}
